User/saulg/fuzzer#325
Conversation
Introduces an `mxc_fuzz` crate at `src/fuzz/` with three libFuzzer targets that cover the attacker-influenced JSON / base64 config surface consumed by `wxc-exec` and `lxc-exec`: - `config_parser`: feeds raw JSON into `load_mxc_request`. - `base64_decode`: same entry point with `is_base64 = true` to cover the SDK-supplied wire format end to end. - `validator`: parses, then runs successful one-shot requests through `validate_common`. The crate is excluded from the parent Cargo workspace so `libfuzzer-sys` and the nightly-only `-Z sanitizer=address` flag are only pulled in when fuzzing. Seed corpora are curated one-per-shape from `test_configs/` (26 / 26 / 11 files). OneFuzz expands the corpus across daily runs. Local smoke test on Windows x64 with nightly Rust + ASAN: all three targets compile and run cleanly with no findings against the seed corpus (~6k-28k exec/s, 81-86 edges of coverage on the parse target). Platform coverage: targets are pure Rust (`wxc_common`) and are cross-platform, so the same source compiles on Linux / macOS. We run them under OneFuzz on Windows only because (a) OneFuzz supports only Windows, Ubuntu, AzureLinux3, and TKO -- macOS is not a supported OneFuzz platform, and (b) for these parser targets the bugs are platform-independent, so a single OS gives full coverage of the relevant code paths. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- `src/fuzz/OneFuzzConfig.json`: manifest for the three libFuzzer targets. Routing fields (Owners, AssignedTo, NotificationEmail, Project, AreaPath, IterationPath) are placeholders pending DRI input; they can be filled in without rebuilding any code. Validate with `oip.exe validate` before the first submission. - `.azure-pipelines/templates/Fuzz.Build.Job.yml`: 1ES PT job that installs nightly Rust + cargo-fuzz, builds with AddressSanitizer, stages the OneFuzz drop directory (per-fuzzer subdir with .exe + ASAN runtime DLL + seed corpus), publishes the drop as a pipeline artifact, and submits via `onefuzz-task@0`. Submission is skipped on PR runs. - `.azure-pipelines/Fuzz.Build.yml`: top-level pipeline. `pr: none`, `trigger: none`, daily 00:00 UTC cron on `main`. Extends the 1ES Unofficial template (no ESRP signing -- the binaries are ASAN- instrumented and only ever consumed by OneFuzz). - `docs/fuzzing.md` and `src/fuzz/README.md`: how to run targets locally, minimize the corpus, and triage bugs filed by OneFuzz. Cargo registry stays pointed at Mxc-Azure-Feed in CI so all crate sources still come from the internal feed; only the rustc/cargo binaries come from rustup nightly. A TODO is left to migrate to a Microsoft-published nightly via msrustup once one is available. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Reverts to trigger: none before merge to main; bring-up only. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds a fuzzing setup to MXC focused on the attacker-influenced config parsing/validation surface in wxc_common, with local cargo-fuzz harnesses and a scheduled Azure Pipelines job that stages and submits fuzzers to OneFuzz.
Changes:
- Introduces a standalone
mxc_fuzzcrate (src/fuzz/) with 3 libFuzzer targets (config_parser,base64_decode,validator) and curated seed corpora. - Adds a daily scheduled Azure Pipelines definition + job template to build the fuzzers with AddressSanitizer and submit to OneFuzz.
- Adds end-user documentation for local and CI fuzzing workflows.
Reviewed changes
Copilot reviewed 74 out of 74 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| src/fuzz/README.md | Local usage docs for cargo-fuzz targets and artifacts/corpus handling. |
| src/fuzz/OneFuzzConfig.json | OneFuzz job manifest describing 3 fuzzing jobs and ADO routing. |
| src/fuzz/fuzz_targets/validator.rs | Fuzz target that parses input and runs validate_common for one-shot requests. |
| src/fuzz/fuzz_targets/config_parser.rs | Fuzz target for load_mxc_request with raw JSON input. |
| src/fuzz/fuzz_targets/base64_decode.rs | Fuzz target for load_mxc_request with base64-encoded input. |
| src/fuzz/corpus/validator/basic_lpac.json | Seed corpus input (validator target). |
| src/fuzz/corpus/validator/basic_lxc.json | Seed corpus input (validator target). |
| src/fuzz/corpus/validator/basic_permissive.json | Seed corpus input (validator target). |
| src/fuzz/corpus/validator/basic_processcontainer.json | Seed corpus input (validator target). |
| src/fuzz/corpus/validator/containment_process_intent.json | Seed corpus input (validator target). |
| src/fuzz/corpus/validator/hello_world_v050.json | Seed corpus input (validator target). |
| src/fuzz/corpus/validator/hyperlight_fs.json | Seed corpus input (validator target). |
| src/fuzz/corpus/validator/hyperlight_hello.json | Seed corpus input (validator target). |
| src/fuzz/corpus/validator/isolation_session_filesystem.json | Seed corpus input (validator target). |
| src/fuzz/corpus/validator/isolation_session_hello.json | Seed corpus input (validator target). |
| src/fuzz/corpus/validator/isolation_session_state_aware_exec_basic.json | Seed corpus input (validator target). |
| src/fuzz/corpus/validator/isolation_session_state_aware_provision.json | Seed corpus input (validator target). |
| src/fuzz/corpus/validator/isolation_session_state_aware_stop.json | Seed corpus input (validator target). |
| src/fuzz/corpus/validator/lxc_filesystem_test.json | Seed corpus input (validator target). |
| src/fuzz/corpus/validator/microvm_error.json | Seed corpus input (validator target). |
| src/fuzz/corpus/validator/microvm_hello.json | Seed corpus input (validator target). |
| src/fuzz/corpus/validator/microvm_timeout.json | Seed corpus input (validator target). |
| src/fuzz/corpus/validator/network_default_test.json | Seed corpus input (validator target). |
| src/fuzz/corpus/validator/network_firewall_test.json | Seed corpus input (validator target). |
| src/fuzz/corpus/validator/rejected_version_too_old.json | Seed corpus input (validator target). |
| src/fuzz/corpus/validator/windows_sandbox_echo.json | Seed corpus input (validator target). |
| src/fuzz/corpus/validator/windows_sandbox_powershell.json | Seed corpus input (validator target). |
| src/fuzz/corpus/validator/windows_sandbox_timeout.json | Seed corpus input (validator target). |
| src/fuzz/corpus/validator/wslc_custom_registry.json | Seed corpus input (validator target). |
| src/fuzz/corpus/validator/wslc_filesystem.json | Seed corpus input (validator target). |
| src/fuzz/corpus/validator/wslc_python_hello.json | Seed corpus input (validator target). |
| src/fuzz/corpus/config_parser/basic_lpac.json | Seed corpus input (config_parser target). |
| src/fuzz/corpus/config_parser/basic_lxc.json | Seed corpus input (config_parser target). |
| src/fuzz/corpus/config_parser/basic_permissive.json | Seed corpus input (config_parser target). |
| src/fuzz/corpus/config_parser/basic_processcontainer.json | Seed corpus input (config_parser target). |
| src/fuzz/corpus/config_parser/containment_process_intent.json | Seed corpus input (config_parser target). |
| src/fuzz/corpus/config_parser/hello_world_v050.json | Seed corpus input (config_parser target). |
| src/fuzz/corpus/config_parser/hyperlight_fs.json | Seed corpus input (config_parser target). |
| src/fuzz/corpus/config_parser/hyperlight_hello.json | Seed corpus input (config_parser target). |
| src/fuzz/corpus/config_parser/isolation_session_filesystem.json | Seed corpus input (config_parser target). |
| src/fuzz/corpus/config_parser/isolation_session_hello.json | Seed corpus input (config_parser target). |
| src/fuzz/corpus/config_parser/isolation_session_state_aware_exec_basic.json | Seed corpus input (config_parser target). |
| src/fuzz/corpus/config_parser/isolation_session_state_aware_provision.json | Seed corpus input (config_parser target). |
| src/fuzz/corpus/config_parser/isolation_session_state_aware_stop.json | Seed corpus input (config_parser target). |
| src/fuzz/corpus/config_parser/lxc_filesystem_test.json | Seed corpus input (config_parser target). |
| src/fuzz/corpus/config_parser/microvm_error.json | Seed corpus input (config_parser target). |
| src/fuzz/corpus/config_parser/microvm_hello.json | Seed corpus input (config_parser target). |
| src/fuzz/corpus/config_parser/microvm_timeout.json | Seed corpus input (config_parser target). |
| src/fuzz/corpus/config_parser/network_default_test.json | Seed corpus input (config_parser target). |
| src/fuzz/corpus/config_parser/network_firewall_test.json | Seed corpus input (config_parser target). |
| src/fuzz/corpus/config_parser/rejected_version_too_old.json | Seed corpus input (config_parser target). |
| src/fuzz/corpus/config_parser/windows_sandbox_echo.json | Seed corpus input (config_parser target). |
| src/fuzz/corpus/config_parser/windows_sandbox_powershell.json | Seed corpus input (config_parser target). |
| src/fuzz/corpus/config_parser/windows_sandbox_timeout.json | Seed corpus input (config_parser target). |
| src/fuzz/corpus/config_parser/wslc_custom_registry.json | Seed corpus input (config_parser target). |
| src/fuzz/corpus/config_parser/wslc_filesystem.json | Seed corpus input (config_parser target). |
| src/fuzz/corpus/config_parser/wslc_python_hello.json | Seed corpus input (config_parser target). |
| src/fuzz/corpus/base64_decode/basic_lxc.b64.txt | Seed corpus input (base64_decode target). |
| src/fuzz/corpus/base64_decode/basic_processcontainer.b64.txt | Seed corpus input (base64_decode target). |
| src/fuzz/corpus/base64_decode/empty.txt | Seed corpus input (base64_decode target). |
| src/fuzz/corpus/base64_decode/hello_world_v050.b64.txt | Seed corpus input (base64_decode target). |
| src/fuzz/corpus/base64_decode/invalid_chars.txt | Seed corpus input (base64_decode target). |
| src/fuzz/corpus/base64_decode/isolation_session_hello.b64.txt | Seed corpus input (base64_decode target). |
| src/fuzz/corpus/base64_decode/microvm_hello.b64.txt | Seed corpus input (base64_decode target). |
| src/fuzz/corpus/base64_decode/padding_only.txt | Seed corpus input (base64_decode target). |
| src/fuzz/corpus/base64_decode/unpadded.txt | Seed corpus input (base64_decode target). |
| src/fuzz/corpus/base64_decode/valid_hello.txt | Seed corpus input (base64_decode target). |
| src/fuzz/corpus/base64_decode/windows_sandbox_echo.b64.txt | Seed corpus input (base64_decode target). |
| src/fuzz/Cargo.toml | Defines mxc_fuzz crate dependencies and fuzz target bins. |
| src/fuzz/.gitignore | Ignores fuzz-specific build outputs, artifacts, and coverage. |
| src/Cargo.toml | Excludes src/fuzz from the Rust workspace. |
| docs/fuzzing.md | End-to-end documentation for fuzzing locally and via the CI pipeline. |
| .azure-pipelines/templates/Fuzz.Build.Job.yml | Pipeline job template to build ASAN fuzzers and stage a OneFuzz drop. |
| .azure-pipelines/Fuzz.Build.yml | Scheduled daily pipeline definition to run the fuzz build + submit stage. |
Remove branch-trigger used during bring-up validation. The pipeline will only run on the daily cron schedule (00:00 UTC on main). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- OneFuzzConfig.json: Update FuzzerExe, JobDependencies, and Seeds paths to include target subdirectory prefix (matches pipeline staging layout: <target>/<exe>, <target>/corpus) - OneFuzzConfig.json: Replace TODO placeholders with real ADO routing (Project: OS, AreaPath: OS\Windows Client and Services\WinPD\ AgOS-Agentic Platform\Agent Runtime\Tessera) - README.md: Fix relative paths (already cd'd into src/fuzz) - docs/fuzzing.md: Fix artifact paths to be relative to src/fuzz Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
| # Nightly Rust toolchain: cargo-fuzz requires `-Z sanitizer=address`, which | ||
| # only nightly accepts. The Mxc-Azure-Feed (`ms-prod-*`) toolchains are | ||
| # stable-only today, so we install nightly via `rustup-init` here. | ||
| # TODO(SFI): switch to a Microsoft-published nightly via msrustup once one | ||
| # is available in Mxc-Azure-Feed; until then keep cargo registry pointed at | ||
| # Mxc-Azure-Feed so all *crate* sources still come from the internal feed. |
There was a problem hiding this comment.
question: Is this something I need to add? I can check and get back to you
There was a problem hiding this comment.
unsure, haven't been able to test the azure side since in order to generate the pipeline the code has to be check in. I couldn't reference a non checked in file.
There was a problem hiding this comment.
all good, lets check it in so you can try it out. There is a way to do it without having to check it in though if I recall but it's ok lets get it in.
- Remove bring-up branch comment from Fuzz.Build.yml (bbonaby) - Use test_configs/ as seed corpus for config_parser and validator targets instead of maintaining duplicated files in src/fuzz/corpus/ (bbonaby) - Keep src/fuzz/corpus/base64_decode/ for pre-encoded seeds - Update pipeline staging to copy from test_configs/*.json - Enhance validator fuzz target to call runner-specific validate_runner based on containment backend (bbonaby). NanVix always available; Hyperlight and IsolationSession behind opt-in features. - Build validator target with --features hyperlight,isolation_session in CI - Update README and docs/fuzzing.md to reflect new corpus source Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The CodexRequest field is named containment, not containment_backend. The fuzz target was failing to build with E0609. Verified locally by running the validator target for 30s under cargo-fuzz (485k runs, no findings). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
| @@ -0,0 +1,55 @@ | |||
| # mxc_fuzz | |||
There was a problem hiding this comment.
suggestion: Might be worth it for us to have a table at the bottom with what each base64_decode relates to since they won't be human readable
| # Nightly Rust toolchain: cargo-fuzz requires `-Z sanitizer=address`, which | ||
| # only nightly accepts. The Mxc-Azure-Feed (`ms-prod-*`) toolchains are | ||
| # stable-only today, so we install nightly via `rustup-init` here. | ||
| # TODO(SFI): switch to a Microsoft-published nightly via msrustup once one | ||
| # is available in Mxc-Azure-Feed; until then keep cargo registry pointed at | ||
| # Mxc-Azure-Feed so all *crate* sources still come from the internal feed. |
There was a problem hiding this comment.
all good, lets check it in so you can try it out. There is a way to do it without having to check it in though if I recall but it's ok lets get it in.
📖 Description
Adds continuous fuzzing infrastructure for MXC's config-parsing surface using cargo-fuzz (libFuzzer) + OneFuzz.
What's included:
config_parser,base64_decode,validatorFuzz.Build.yml) with daily cron schedule onmaindocs/fuzzing.mdandsrc/fuzz/README.mdPipeline behavior:
trigger: none/pr: none— only runs on daily cron (00:00 UTC)🔍 Validation
✅ Checklist
📋 Issue Type